<?php
header("Content-type:text/html;Charset=utf-8");

//抽象访问者接口,定义具体访问者要实现的方法，访问不同元素调用不同方法
abstract class Visitor{
    abstract function eat($place);
    abstract function work($place);
}
//具体访问者角色
class ConcreteVisitor extends Visitor{
    //回家吃饭
    function eat($place){
        echo "回".$place->name."吃饭";
    }
    //去公司上班
    function work($place){
        echo "去".$place->name."上班";
    }
}


//抽象元素，定义一个接受访问操作acceptVisitor()，它以一个访问者作为参数。
abstract class Place{
    abstract function acceptVisitor(Visitor $visitor);
}

//具体元素，实现抽象元素所定义的接受操作接口
//家，访问者回家吃饭
class Homn extends Place{
    public $name;

    function __construct($name){
        $this->name = $name;
    }

    function acceptVisitor(Visitor $visitor){
        $visitor->eat($this);
    }
}

//公司，访问者来公司上班
class Company extends Place{
    public $name;

    function __construct($name){
        $this->name = $name;
    }

    function acceptVisitor(Visitor $visitor){
        $visitor->work($this);
    }
}

//树形结构对象，即元素集合
class ObjectStruction{
    private $places = array();

    //增加元素
    function addPlace(Place $place){
        $this->places[] = $place;
    }
    //去除元素
    function removePlace(Place $place){
        $key = array_search($place, $this->places);
        if($key !== false){
            unset($this->places[$key]);
        }
    }
    //元素集合所有元素接受访问
    function allAccept(Visitor $visitor)  {
        foreach ($this->places as $place)
        {
            $place->acceptVisitor($visitor);
        }
    }
}

//测试
$objectStruction = new ObjectStruction();
$home = new Homn("家");
$objectStruction->addPlace($home);
$company = new Company("公司");
$objectStruction->addPlace($company);

$visitor = new ConcreteVisitor();
$objectStruction->allAccept($visitor);

?>